#============================================================
#    StateNode
#============================================================
# - datetime: 2022-12-01 12:48:31
#============================================================
## 状态节点
class_name StateNode
extends Node


## 进入当前状态
signal entered_state(data: Dictionary)
## 退出当前状态
signal exited_state
## 状态发生切换。[code]previous[/code]上个状态名称，[code]current[/code]当前状态名，
##[code]data[/code]当前状态进入时传入的数据
signal state_changed(previous: StringName, current: StringName, data: Dictionary)


## 自动启动第一个子状态
@export
var auto_start : bool = false


var _name_to_state_map := {}
var _state_to_name_map := {}
var _current_state : StringName = &""


var __readied = self.ready.connect( func():
	# 如果不作判断，继承这个脚本的脚本会重复执行这个内容
	if self['__readied']:
		return
	
	for child in get_children():
		if child is StateNode:
			register_state(child.name, child)
	
	set_physics_process(false)
	
	if auto_start:
		if not _name_to_state_map.is_empty():
			var first = _name_to_state_map.keys()[0]
			start(first)
	
	self['__readied'] = true
)


#============================================================
#  SetGet
#============================================================
## 添加状态
func add_state(state: StringName):
	var node = StateNode.new()
	register_state(state, node)
	node.name = state
	add_child(node, true)

## 获取子级状态节点
func get_state_node(state: StringName) -> StateNode:
	return _name_to_state_map.get(state) as StateNode

## 获取当前执行的子级状态名称
func get_current_state() -> StringName:
	return _current_state

## 获取当前状态节点
func get_current_state_node() -> StateNode:
	return get_state_node(get_current_state()) if _current_state else null

## 注册状态
func register_state(state: StringName, node: StateNode):
	if _name_to_state_map.has(state):
		printerr("已经添加过 ", state, " 状态")
	_name_to_state_map[state] = node
	_state_to_name_map[node] = state



#============================================================
#  内置
#============================================================
func _physics_process(delta: float) -> void:
	(_name_to_state_map[_current_state] as StateNode)._state_process(delta)



#============================================================
#  可重写
#============================================================
func _enter_state(data: Dictionary):
	pass


func _exit_state():
	pass


func _state_process(delta: float):
	pass



#============================================================
#  自定义
#============================================================
## 进入状态
func enter_state(data: Dictionary):
	_enter_state(data)
	entered_state.emit(data)
	if not _name_to_state_map.is_empty():
		set_physics_process(true)


## 退出状态
func exit_state():
	_exit_state()
	exited_state.emit()
	set_physics_process(false)


## 启动状态机
func start(state: String, data: Dictionary = {}):
	if _name_to_state_map.has(state):
		assert(not _name_to_state_map.is_empty(), "没有添加子状态！")
		set_physics_process(true)
		if _current_state == &"":
			_current_state = state
			get_state_node(state).enter_state(data)
		else:
			printerr(self, "状态机已经启动！")
	else:
		printerr(self, "没有这个状态机！state_name = ", state)


## 切换状态
func trans_to(state: StringName, data: Dictionary = {}):
	assert(_current_state != &"", "状态机还未启动！")
	if _name_to_state_map.has(state):
		var previous_state = _current_state
		get_state_node(previous_state).exit_state()
		
		_current_state = state
		get_state_node(state).enter_state(data)
		state_changed.emit( previous_state, state, data )
		
	else:
		printerr(self, "没有这个子状态！ state = ", state)


## 父节点切换状态
func parent_trans_to(state: StringName, data: Dictionary = {}):
	get_parent().trans_to(state, data)

